/**
 * Copyright (c) suzuki ryoutoku
 * See this code regarding the Apache License Version 2.0
 * @author suzuki ryoutoku
 */


//=============================================================================
//	Protected multiple include file
//=============================================================================
#ifndef READER_H
#define READER_H

//=============================================================================
//	Preprocessor
//=============================================================================
#include "include/declare.h"
#include "mathematics/Mathematics.h"
#include <fstream>
#include <vector>
#include <stack>
#include <cstring>
using namespace std;

//=============================================================================
//	declare local class & function
//=============================================================================
namespace reader{
  /**
   * Reader of 3ds use these classes & function 
   */
  namespace max{
	class Object;
	class FaceGroup;
	class Material;
	class Chunk;
	unsigned int getName(FILE* fp, char* name);
  }

  namespace vdf{
	class Attribute;
  }

  namespace pcm{
	class Volume;
	class Vertex;
  }
}

//=============================================================================
//	Define enum type
//=============================================================================
/**
 * 3DS file's chunk id
 * \note
 * Sign EDIT3DS is to express starting actually data.
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2008-2-5
 */
enum StudioMaxChunk{
  EDIT3DS           = 0x3D3D,
  AMBIENT_LIGHT     = 0X2100,
  OBJECT            = 0x4000,
  OBJECT_MESH       = 0x4100,
  MESH_VERTICES     = 0x4110,
  MESH_FACES        = 0x4120,
  MESH_TEXTURE_COORD= 0x4140,
  MESH_MATERIAL     = 0x4130,
  MATERIAL          = 0xAFFF,
  MATERIAL_NAME     = 0xA000,
  MATERIAL_DIFFUSE  = 0xA020,
  MATERIAL_TEXMAP   = 0xA200,
  MATERIAL_TEXFILE  = 0xA300,
};

//=============================================================================
//	Define class
//=============================================================================
/**
 * This class is super class for all classes reding 3d data file.
 * @author suzuki ryoutoku 
 * @date 2007-10-14
 * @version 1.0
 */
class library::graphics::Reader
{
  // closed member
protected:
  library::log::LogManager*	 _log_manager;//!< Log manager class
  vector<string>			 _texfilename;//!< Name of file of Texture data

  // opened class member
public:
  const static int  NumberOfCharactersLine;
  const static char* Comment[];

  // opened method
public:
  Reader(library::log::LogManager* arg);
  ~Reader();

  virtual library::graphics::Model* read(const string& filename) = 0;

  vector<string>* get_texfilename(){return &(_texfilename);}
  bool isExisting(const char* filename);
  
  // open class method
public:
  static bool CheckLine(string* arg);
  static int CountData(const string& arg, const string specify = " " );
  static void ExtractModelName(const string& arg, char* model);
  static library::graphics::Reader* CreateReader(const string& filename,
												 library::log::LogManager* arg);
};

/**
 * This class allow you to load a 3ds file (it's for 3D Studio max).
 * \note
 * 3ds is dedicated file of 3D Studio Max.
 * When I writing this class, Following url is used as reference.
 * http://www.spacesimulator.net/tut4_3dsloader.html
 * [Usage]
 * 1. You create instance of this class.
 * 2. You call this class's read3DSFile method, then argument must be 3ds 
 * file name.
 *
 * @author suzuki ryoutoku 
 * @date 2008-1-2
 * @version 1.0
 */
class library::graphics::Read3ds
  : public library::graphics::Reader
{
  // closed member
private:
  vector<reader::max::Object*>	   m_objects;//!< This is express meshes in 3ds
  stack<reader::max::Object*>	   m_cobject;/**<
												This stack is current mesh,
												Mesh data is since recursive 
												in 3ds file.
											 */
  vector<reader::max::Material*> _material;
  stack<reader::max::Material*> m_cmaterial;


  // opened method
public:
  Read3ds(library::log::LogManager* arg);
  ~Read3ds();
  library::graphics::Model* read(const string& filename);

  // closed methods
private:
  void readMesh(FILE* fp, reader::max::Chunk* head);
  void readMeshVertices(FILE* fp, reader::max::Chunk* head);
  void readMeshFaces(FILE* fp, reader::max::Chunk* head);
  void readMeshMaterial(FILE* fp, reader::max::Chunk* head);
  void readMeshTextureCoord(FILE* fp, reader::max::Chunk* head);
  void readObject(FILE* fp, reader::max::Chunk* head);
  void readDiffuse(FILE* fp, reader::max::Chunk* head);
  void readMaterial(FILE* fp, reader::max::Chunk* head);
  void readEdit3ds(FILE* fp, reader::max::Chunk* head);

  library::graphics::Model* createModelData(void);

  unsigned int getMaterialIndex(const char* name) throw (char*);

  void setTexfilename(void);
};


class reader::pcm::Vertex
{
public:
  int 							   _global_id;
  library::mathematics::Vector<double> _coord;
};

/**
 * This class is enable to read pcm file.
 * \note
 * PCM format is input file of Adventure TetMesh.
 * most particulary
 * @author r-suzuki
 * @date 2009-1-17
 * @version 1.0
 */
class library::graphics::ReadPcm
  : public library::graphics::Reader
{
private:
  vector<reader::pcm::Vertex>					_coord;
  vector<reader::pcm::Volume*>				  _volumes;
  
  // opened method
public:
  ReadPcm(library::log::LogManager* arg);
  ~ReadPcm();
  library::graphics::Model* read(const string& filename);

private:
  int readHeader(ifstream& fin);
  int readVertexTerm(ifstream& fin);
  int readVolumeTerm(ifstream& fin, size_t index);
  library::graphics::Model* createModel(void);

};

/**
 * A volume data in pcm file.
 * This class is used when reading pcm file.
 * @author r-suzuki
 * @version 1.0
 */
class reader::pcm::Volume
{
private:
  vector<int>	_node_localindex;
  vector<int>		   _facetype;
  vector<int>	   		  _conne;
public:
  ~Volume();
  int createNodeLocalIndex(void);
  library::graphics::Cluster* createCluster(library::graphics::PolygonBody*, 
											int type);
  

public:
  friend class library::graphics::ReadPcm;

public:
  enum FaceType{
	NONE		= 0x00,
	SEGMENT 	= 0x02,
	TRIANGLE	= 0x03,
	RECTANGLE	= 0x04,
  };
};

/**
 * The class is header of chunk in 3ds file.
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2008-2-5
 */
class reader::max::Chunk
{
public:
  unsigned short m_ID;
  unsigned int m_length;
  unsigned int m_bytesread;

public:
  Chunk();
  void display(void);
  unsigned int readFile(FILE* fp);
  unsigned int skipFile(FILE* fp);

public:
  static unsigned int DATASIZE;
};

/**
 * The class express Object data in 3d studio max.
 * @author suzuki ryoutoku 
 * @date 2008-1-2
 * @version 1.0
 */
class reader::max::Object
{
  // closed member
private:
  char					 		 m_name[20];//!< Length of name in max is 20.
  unsigned int					m_vertexsum;
  vector<float>		     			m_coord;
  unsigned int		  		  m_trianglesum;
  vector<unsigned short>			m_index;
  unsigned int						m_uvsum;
  vector<float>						   m_uv;
  vector<reader::max::FaceGroup*>	m_group;
  int		 		 m_last_total_vertexsum;/**< 
											   when creating model data, 
											   it's used.
											*/
  
  // opened method
public:
  Object();
  ~Object();
  bool isModelData(void);
  unsigned int queryGroupSum(void);

  // inline setter & getter
public:
  void setM_name(char* arg){strcpy(m_name,arg);}

  // friend class
public:
  friend class library::graphics::Read3ds;
};

/**
 * This class roles Material informations in 3ds file.
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2008-2-20
 */
class reader::max::Material
{
  // closed member
private:
  char				m_name[20];
  unsigned char	  m_diffuse[3];
  char	m_texture_filename[20];

  // opened method
public:
  Material();
  ~Material();

  // inline setter & getter
public:
  void setM_name(char* arg){strcpy(m_name,arg);}

  void setM_texture_filename(char* arg){strcpy(m_texture_filename,arg);}
  char* getM_texture_filename(void){return m_texture_filename;}
  
public:
  friend class library::graphics::Read3ds;
};


/**
 * This class is used when reading 3ds file.
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2008-2-15
 */
class reader::max::FaceGroup
{
  // closed member
private:
  char		   m_materialname[20];
  vector<unsigned short>  m_faces;
  
  // opened method
public:
  FaceGroup();
  ~FaceGroup();

  // inline setter & getter
public:
  void setM_materialname(char* arg){strcpy(m_materialname,arg);}

public:
  friend class library::graphics::Read3ds;
  friend class reader::max::Object;
};

/**
 * This class role is reading Original format 'vdf'.
 * @author r-suzuki
 * @date 2008-12-8
 * @version 1.0
 */
class library::graphics::ReadVdf
  : public library::graphics::Reader
{
private:
  vector<library::graphics::PolygonBody*>	_bodies;
  library::graphics::PolygonBody*	  _current_body;
  
public:
  ReadVdf(library::log::LogManager* arg);
  ~ReadVdf();
  library::graphics::Model* read(const string& filename);

private:
  unsigned int readLabel(const string& label);
  bool readPolygonBody(ifstream& fin);
  bool readNodalCoordinate(ifstream& fin);
  bool readUV(ifstream& fin);
  bool readRectangleCluster(ifstream& fin);
  bool readTriangleCluster(ifstream& fin);
  bool readGroup(ifstream& fin);

  bool readAttribute(ifstream& fin, reader::vdf::Attribute* attr);

public:
  enum LabelType{
	NONE,
	BODY,
	NODAL_COORDNAITE,
	UV,
	RECTANGLE_CLUSTER,
	TRIANGLE_CLUSTER,
	GROUP,
  };
};


/**
 * This class express a attribute of a chunk in vdf file.
 * @author r-suzuki
 * @date 2008-12-9
 * @version 1.0
 */
class reader::vdf::Attribute
{
private:
  int		   	 	_id;
  int	  	 _target_id;
  int		   	  _type;
  int	   _target_type;
  char	  	 _name[256];
  char	_data_name[256];
  int			   _sum;
public:
  friend class library::graphics::ReadVdf;
  Attribute();
};

#endif
